/*
 * Copyright 2020 Echedey López Romero.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Maneja el entorno de trabajo para realizar las operaciones de administración
 * de sistemas de una forma sencilla.
 *
 * @author Echedey López Romero
 */
public class InterfazAdministracionSistemas {

	private Scanner teclado;
	private EntornoTrabajo entorno;

	/**
	 * Define la herramienta de entrada y el entorno de trabajo mediante
	 * crearEntorno.
	 */
	public InterfazAdministracionSistemas() {
		teclado = new Scanner(System.in);
		EntornoTrabajo nuevoentorno = crearEntorno();

		if (nuevoentorno != null) {
			entorno = nuevoentorno;
		} else {
			throw new NullPointerException("No se puede usar la app sin definir el entorno de trabajo.");
		}
	}

	/**
	 * Crea el entorno de trabajo con datos solicitados al usuario por teclado.
	 *
	 * @return entorno de trabajo
	 */
	private EntornoTrabajo crearEntorno() {
		System.out.println("Bienvenido a la demo de Administración de Sistemas.");

		System.out.print("Introduzca la ruta del fichero de datos: ");
		String ruta = teclado.next();

		System.out.print("Introduzca el nombre del entorno de trabajo: ");
		String nombre = teclado.next();

		System.out.print("Introduzca el lugar donde se encuentra el entorno de trabajo: ");
		String lugar = teclado.next();

		EntornoTrabajo entorno = null;

		try {
			entorno = new EntornoTrabajo(ruta, nombre, lugar);
		} catch (NullPointerException ex) {
			System.out.println(ex.getMessage());
		}

		return entorno;
	}

	/**
	 * Inicia la interfaz.
	 */
	public void iniciar() {
		borrarPantalla();

		String opcion = menu();

		while (!opcion.equalsIgnoreCase("f")) {
			switch (opcion.toLowerCase()) {
				case "a1": {
					try {
						entorno.leerEntorno();
					} catch (FileNotFoundException ex) {
						System.out.println("No se ha podido encontrar el fichero.");
					} catch (IOException ex) {
						System.out.println("No se ha podido acceder al fichero para la lectura.");
					}
				}
				break;
				case "a2":
				{
					try {
						entorno.guardarEntorno();
					} catch (IOException ex) {
						System.out.println("No se ha podido acceder al fichero para la escritura.");
					}
				}
					break;

				case "b1":
					habilitarEquipo();
					break;
				case "b2": {
					System.out.print("Introduce un número de equipo: ");
					int numero = teclado.nextInt();
					boolean tirado = entorno.tirarEquipo(numero);

					if (tirado) {
						System.out.println("Equipo eliminado satisfactoriamente.");
					} else {
						System.out.println("Se ha introducido un número de equipo inexistente.");
					}
				}
				break;
				case "b3":
					mantenerEquipo();
					break;
				case "c1":
					instalarSoftwareEquipo();
					break;
				case "c2":
					instalarSoftwareGeneral();
					break;
				case "c3":
					desinstalarSoftwareEquipo();
					break;
				case "c4":
					desinstalarSoftwareGeneral();
					break;
				case "c5":
					mantenerSoftwareEquipo();
					break;
				case "c6":
					mantenerSoftwareGeneral();
					break;
				case "d1": {
					System.out.print("Introduce un número de equipo: ");
					int numero = teclado.nextInt();

					try {
						Equipo equipo = entorno.buscarNumero(numero);
						entorno.imprimirEquipos(equipo, null, null);
					} catch (NullPointerException | IllegalArgumentException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "d2": {
					System.out.print("Introduce un procesador: ");
					String procesador = teclado.next();

					try {
						List<Integer> numeros = entorno.buscarProcesador(procesador);
						entorno.imprimirEquipos(null, null, numeros);
					} catch (NullPointerException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "d3": {
					System.out.print("Introduce una cantidad de memoria RAM en MB mayor a 1024: ");
					int memoria = teclado.nextInt();

					try {
						List<Integer> numeros = entorno.buscarMemoria(memoria);
						entorno.imprimirEquipos(null, null, numeros);
					} catch (NullPointerException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "d4": {
					System.out.print("Introduce una capacidad de almacenamiento mayor en GB mayor a 40.0: ");
					float almacenamiento = teclado.nextFloat();

					try {
						List<Integer> numeros = entorno.buscarAlmacenamiento(almacenamiento);
						entorno.imprimirEquipos(null, null, numeros);
					} catch (NullPointerException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "d5":
					buscarSoftware();
					break;
				case "e1":
					System.out.println(entorno.toString());
					break;
				case "e2": {
					try {
						List<Equipo> ordenado = entorno.ordenarEquipos(1);
						entorno.imprimirEquipos(null, ordenado, null);
					} catch (IllegalArgumentException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "e3": {
					try {
						List<Equipo> ordenado = entorno.ordenarEquipos(2);
						entorno.imprimirEquipos(null, ordenado, null);
					} catch (IllegalArgumentException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
				case "e4": {
					try {
						List<Equipo> ordenado = entorno.ordenarEquipos(3);
						entorno.imprimirEquipos(null, ordenado, null);
					} catch (IllegalArgumentException ex) {
						System.out.println(ex.getMessage());
					}
				}
				break;
			}
			
			opcion = menu();
		}
	}

	/**
	 * Crea un menú interactivo para realizar distintas operaciones.
	 *
	 * @return codigo de opción
	 */
	private String menu() {
		System.out.println("\n MENU PRINCIPAL \n");
		System.out.println("a. Entorno de trabajo: ");
		System.out.println("\t 1. Leer datos.");
		System.out.println("\t 2. Guardar datos.");
		System.out.println("b. Operaciones sobre los equipos: ");
		System.out.println("\t 1. Habilitar.");
		System.out.println("\t 2. Tirar.");
		System.out.println("\t 3. Mantener.");
		System.out.println("c. Operaciones sobre el software: ");
		System.out.println("\t 1. Instalar en un equipo.");
		System.out.println("\t 2. Instalar en todos.");
		System.out.println("\t 3. Desinstalar en un equipo.");
		System.out.println("\t 4. Desinstalar en todos.");
		System.out.println("\t 5. Mantener en un equipo.");
		System.out.println("\t 6. Mantener en todos.");
		System.out.println("d. Búsquedas: ");
		System.out.println("\t 1. Por número de equipo.");
		System.out.println("\t 2. Por procesador.");
		System.out.println("\t 3. Por cantidad de memoria RAM.");
		System.out.println("\t 4. Por capacidad de almacenamiento.");
		System.out.println("\t 5. Por software instalado.");
		System.out.println("e. Listados: ");
		System.out.println("\t 1. Entorno completo.");
		System.out.println("\t 2. Equipos por marca y modelo.");
		System.out.println("\t 3. Equipos por cantidad de memoria RAM.");
		System.out.println("\t 4. Equipos por capacidad de almacenamiento.");
		System.out.println("f. Finalizar aplicación.");
		System.out.print("\n Escoge una opción (ej. c1): ");

		return teclado.next();
	}

	/**
	 * Borra el contenido de la pantalla.
	 */
	private void borrarPantalla() {
		System.out.print('\u000C');
	}

	/**
	 * Añade un equipo nuevo al entorno de trabajo.
	 */
	private void habilitarEquipo() {

		System.out.print("Introduzca una marca: ");
		String marca = teclado.next();

		System.out.print("Introduzca un modelo: ");
		String modelo = teclado.next();

		System.out.print("Introduzca un procesador: ");
		String procesador = teclado.next();

		System.out.print("Introduzca una cantidad de memoria RAM en MB superior a 1024: ");
		int memoria = teclado.nextInt();

		System.out.print("Introduzca una capacidad de almacenamiento en GB superior a 40.0: ");
		float almacenamiento = teclado.nextFloat();

		System.out.print("Introduzca un tipo de Equipo, Ordenador/Servidor (sólo inicial): ");
		String seleccion = teclado.next();

		try {
			if (seleccion == null) {
				System.out.println("No se ha introducido ninguna opcion.");
			} else if (!seleccion.equalsIgnoreCase("o") && !seleccion.equalsIgnoreCase("s")) {
				System.out.println("Se ha introducido una opción incorrecta.");
			} else {
				Equipo equipo;

				if (seleccion.equalsIgnoreCase("o")) {
					equipo = new Ordenador(marca, modelo, procesador, memoria, almacenamiento);
				} else {
					equipo = new Servidor(marca, modelo, procesador, memoria, almacenamiento);
				}

				List<Software> softwares = new ArrayList<>();
				boolean aniadir = true;

				while (aniadir) {

					System.out.print("Indica si añadir software al equipo, Sí/No (solo inicial): ");
					String aniadirstr = teclado.next();

					if (aniadirstr == null) {
						System.out.println("No se ha introducido ninguna opción.");
					} else if (!aniadirstr.equalsIgnoreCase("s") && !aniadirstr.equalsIgnoreCase("n")) {
						System.out.println("Se ha introducido una opción incorrecta.");
					} else {

						if (aniadirstr.equalsIgnoreCase("n")) {
							aniadir = false;
						} else {

							System.out.print("Introduce una compañía: ");
							String compania = teclado.next();

							System.out.print("Introduce un nombre: ");
							String nombre = teclado.next();

							System.out.print("Introduce un número de versión: ");
							double version = teclado.nextDouble();

							System.out.println("Introduce una posesión de licencia, Sí/No (sólo inicial): ");
							String tienelicenciastr = teclado.next();

							System.out.print("Introduce un tipo de software, Sistema Operativo/Aplicación (sólo inicial): ");
							String tipostr = teclado.next();

							if (tienelicenciastr == null) {
								System.out.println("No se ha introducido la posesión de licencia.");
							} else if (tipostr == null) {
								System.out.println("No se ha introducido ningún tipo de software.");
							} else if (!tienelicenciastr.equalsIgnoreCase("s") && !tienelicenciastr.equalsIgnoreCase("n")) {
								System.out.println("Se ha introducido una opción incorrecta en la posesión de licencia.");
							} else if (!tipostr.equalsIgnoreCase("s") && !tipostr.equalsIgnoreCase("a")) {
								System.out.println("Se ha introducido una opción incorrecta en el tipo.");
							} else {
								boolean tienelicencia;
								TipoSoftware tipo;

								if (tienelicenciastr.equalsIgnoreCase("s")) {
									tienelicencia = true;
								} else {
									tienelicencia = false;
								}

								if (tipostr.equalsIgnoreCase("s")) {
									tipo = TipoSoftware.SISTEMAOPERATIVO;
								} else {
									tipo = TipoSoftware.APLICACION;
								}

								Software software = new Software(compania, nombre, version, tienelicencia, tipo);
								softwares.add(software);
							}
						}
					}
				}
				
				boolean habilitado = entorno.habilitarEquipo(equipo, softwares);
				
				if (habilitado) {
					System.out.println("Habilitación realizada satisfactoriamente.");
				} else {
					System.out.println("No se ha podido habilitar el equipo.");
				}
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Actualiza el hardware básico de un equipo.
	 */
	private void mantenerEquipo() {
		System.out.print("Introduce un número de equipo: ");
		int numero = teclado.nextInt();

		System.out.print("Introduce un procesador: ");
		String procesador = teclado.next();

		System.out.print("Introduce una cantidad de memoria RAM en MB superior a 1024: ");
		int memoria = teclado.nextInt();

		System.out.print("Introduce una capacidad de almacenamiento en GB superior a 40.0: ");
		float almacenamiento = teclado.nextFloat();

		try {
			boolean mantenido = entorno.mantenerEquipo(numero, procesador, memoria, almacenamiento);

			if (mantenido) {
				System.out.println("Mantenimiento realizado satisfactoriamente.");
			} else {
				System.out.println("Se ha introducido un número de equipo inexistente.");
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Instala un software en un equipo específico.
	 */
	private void instalarSoftwareEquipo() {
		System.out.print("Introduce un número de equipo: ");
		int numero = teclado.nextInt();

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		System.out.print("Introduce un número de versión: ");
		double version = teclado.nextDouble();

		System.out.println("Introduce una posesión de licencia, Sí/No (sólo inicial): ");
		String tienelicenciastr = teclado.next();

		System.out.print("Introduce un tipo de software, Sistema Operativo/Aplicación (sólo inicial): ");
		String tipostr = teclado.next();

		try {
			if (tienelicenciastr == null) {
				System.out.println("No se ha introducido la posesión de licencia.");
			} else if (tipostr == null) {
				System.out.println("No se ha introducido ningún tipo de software.");
			} else if (!tienelicenciastr.equalsIgnoreCase("s") && !tienelicenciastr.equalsIgnoreCase("n")) {
				System.out.println("Se ha introducido una opción incorrecta en la posesión de licencia.");
			} else if (!tipostr.equalsIgnoreCase("s") && !tipostr.equalsIgnoreCase("a")) {
				System.out.println("Se ha introducido una opción incorrecta en el tipo.");
			} else {
				boolean tienelicencia;
				TipoSoftware tipo;

				if (tienelicenciastr.equalsIgnoreCase("s")) {
					tienelicencia = true;
				} else {
					tienelicencia = false;
				}

				if (tipostr.equalsIgnoreCase("s")) {
					tipo = TipoSoftware.SISTEMAOPERATIVO;
				} else {
					tipo = TipoSoftware.APLICACION;
				}

				Software software = new Software(compania, nombre, version, tienelicencia, tipo);

				List<Integer> fallido = entorno.instalarSoftware(software, numero);

				if (!fallido.isEmpty()) {
					System.out.println("Software instalado satisfactoriamente.");
				} else {
					System.out.println("La instalación ha fallado.");
				}
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Instala un software en todos los equipos.
	 */
	private void instalarSoftwareGeneral() {
		int numero = 0;

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		System.out.print("Introduce un número de versión: ");
		double version = teclado.nextDouble();

		System.out.println("Introduce una posesión, de licencia Sí/No (sólo inicial): ");
		String tienelicenciastr = teclado.next();

		System.out.print("Introduce un tipo de software, Sistema Operativo/Aplicación (sólo inicial): ");
		String tipostr = teclado.next();

		try {
			if (tienelicenciastr == null) {
				System.out.println("No se ha introducido la posesión de licencia.");
			} else if (tipostr == null) {
				System.out.println("No se ha introducido ningún tipo de software.");
			} else if (!tienelicenciastr.equalsIgnoreCase("s") && !tienelicenciastr.equalsIgnoreCase("n")) {
				System.out.println("Se ha introducido una opción incorrecta en la posesión de licencia.");
			} else if (!tipostr.equalsIgnoreCase("s") && !tipostr.equalsIgnoreCase("a")) {
				System.out.println("Se ha introducido una opción incorrecta en el tipo.");
			} else {
				boolean tienelicencia;
				TipoSoftware tipo;

				if (tienelicenciastr.equalsIgnoreCase("s")) {
					tienelicencia = true;
				} else {
					tienelicencia = false;
				}

				if (tipostr.equalsIgnoreCase("s")) {
					tipo = TipoSoftware.SISTEMAOPERATIVO;
				} else {
					tipo = TipoSoftware.APLICACION;
				}

				Software software = new Software(compania, nombre, version, tienelicencia, tipo);

				List<Integer> fallido = entorno.instalarSoftware(software, numero);

				if (!fallido.isEmpty()) {
					System.out.println("Software instalado satisfactoriamente.");
				} else {
					System.out.println("La instalación ha fallado en los siguientes equipos: ");
					entorno.imprimirEquipos(null, null, fallido);
				}
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Desinstala un software en un equipo específico.
	 */
	private void desinstalarSoftwareEquipo() {
		System.out.print("Introduce un número de equipo: ");
		int numero = teclado.nextInt();

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		double version = 1.0;
		boolean tienelicencia = false;
		TipoSoftware tipo = TipoSoftware.SISTEMAOPERATIVO;

		try {
			Software software = new Software(compania, nombre, version, tienelicencia, tipo);

			List<Integer> fallido = entorno.desinstalarSoftware(software, numero);

			if (!fallido.isEmpty()) {
				System.out.println("Software desinstalado satisfactoriamente.");
			} else {
				System.out.println("La desinstalación ha fallado.");
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Desinstala un software en todos los equipos.
	 */
	private void desinstalarSoftwareGeneral() {
		int numero = 0;

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		double version = 1.0;
		boolean tienelicencia = false;
		TipoSoftware tipo = TipoSoftware.SISTEMAOPERATIVO;

		try {
			Software software = new Software(compania, nombre, version, tienelicencia, tipo);

			List<Integer> fallido = entorno.desinstalarSoftware(software, numero);

			if (!fallido.isEmpty()) {
				System.out.println("Software desinstalado satisfactoriamente.");
			} else {
				System.out.println("La desinstalación ha fallado en los siguientes equipos: ");
				entorno.imprimirEquipos(null, null, fallido);
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Realiza el mantenimiento de un software en un equipo específico.
	 */
	private void mantenerSoftwareEquipo() {
		System.out.print("Introduce un número de equipo: ");
		int numero = teclado.nextInt();

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		double version = 1.0;
		boolean tienelicencia = false;
		TipoSoftware tipo = TipoSoftware.SISTEMAOPERATIVO;

		try {
			Software software = new Software(compania, nombre, version, tienelicencia, tipo);

			List<Integer> fallido = entorno.mantenerSoftware(software, numero);

			if (!fallido.isEmpty()) {
				System.out.println("Mantenimiento de software satisfactoriamente.");
			} else {
				System.out.println("El mantenimiento del software ha fallado.");
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Realiza el mantenimiento de un software en todos los equipos.
	 */
	private void mantenerSoftwareGeneral() {
		int numero = 0;

		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		double version = 1.0;
		boolean tienelicencia = false;
		TipoSoftware tipo = TipoSoftware.SISTEMAOPERATIVO;

		try {
			Software software = new Software(compania, nombre, version, tienelicencia, tipo);

			List<Integer> fallido = entorno.mantenerSoftware(software, numero);

			if (!fallido.isEmpty()) {
				System.out.println("Mantenimiento de software satisfactoriamente.");
			} else {
				System.out.println("El mantenimiento del software ha fallado en los siguientes equipos: ");
				entorno.imprimirEquipos(null, null, fallido);
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}

	/**
	 * Busca los equipos o el equipo que tienen instalado un software
	 * específico.
	 */
	private void buscarSoftware() {
		System.out.print("Introduce una compañía: ");
		String compania = teclado.next();

		System.out.print("Introduce un nombre: ");
		String nombre = teclado.next();

		double version = 1.0;
		boolean tienelicencia = false;
		TipoSoftware tipo = TipoSoftware.SISTEMAOPERATIVO;

		try {
			Software software = new Software(compania, nombre, version, tienelicencia, tipo);

			List<Integer> instalado = entorno.buscarSoftware(software);

			if (!instalado.isEmpty()) {
				System.out.println("El software no se encuentra instalado en ningún equipo.");
			} else {
				System.out.println("El software se encuentra instalado en los siguientes equipos: ");
				entorno.imprimirEquipos(null, null, instalado);
			}
		} catch (NullPointerException | IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
	}
}
